using Microsoft.SharePoint.WebPartPages;
using System;
using System.Collections;
using System.ComponentModel;
using System.Web.Caching;
using System.Web.UI;
using System.Xml.Serialization;
using ThoughtWorks.CruiseControl.Remote;

namespace TamTam.SharePoint.CruiseControl {

    /// <summary>
    /// Webpart that connect's to CruiseControl via remoting and display's 
    /// information on the projects.
    /// </summary>
    /// <remarks>uses remoting, and caches the remoting answer for 2 minutes.</remarks>
	[DefaultProperty("Text"), 
    ToolboxData("<{0}:CruiseControlFarmInfo runat=server></{0}:CruiseControlFarmInfo>"),
    XmlRoot(Namespace = "TamTam.SharePoint.CruiseControl")]
	public class CCFarmInfo : WebPart {

        /// <summary>
        /// Empty default constructor
        /// </summary>
		public CCFarmInfo() {
			this.server = "";
		}
        
        /// <summary>
        /// Retrieve the information from CruiseControl via Remoting
        /// </summary>
        /// <returns>An Array of Project Info objects</returns>
		protected ArrayList GetProjectInfo() {
			ArrayList projectlist = null;
			try {
				string cacheKey = "cruisecontrol_farminfo_" + this.Server;
				projectlist = this.Page.Cache[cacheKey] as ArrayList;
				if (projectlist != null) {
					return projectlist;
				}
				projectlist = new ArrayList();
                string remotingurl = string.Format("tcp://{0}:{1}/CruiseManager.rem", this.Server, this.Port);

				RemotingServiceAdapter rsa = new RemotingServiceAdapter();
				
				ICruiseManager man = (ICruiseManager )rsa.Connect(typeof(ICruiseManager), remotingurl);

				ProjectStatus[] statusArray = man.GetProjectStatus();
				foreach (ProjectStatus status in statusArray) {
                    if (string.IsNullOrEmpty(this.Category)) {
                        projectlist.Add(status);
                    }
                    else {
                        if (string.Compare(status.Category, this.Category, true)==0) {
                            projectlist.Add(status);
                        }
                    }
				}

                if (statusArray.GetLength(0) > 0) {
					this.Page.Cache.Add(cacheKey, projectlist, null, DateTime.Now.AddMinutes(2), TimeSpan.Zero, CacheItemPriority.BelowNormal, null);
				}
			}
			catch {
				projectlist = null;
			}
			return projectlist;
		}

        /// <summary>
        /// Force the build of a project 
        /// </summary>
        /// <remarks>project to build is supplied through the querystring</remarks>
        protected void CheckForceBuild() {
            string forcebuild = this.Page.Request.QueryString["force"];
            if (!string.IsNullOrEmpty(forcebuild)) {
                try {
                    // connect to cruisecontrol to send the force build command
                    string remotingurl = string.Format("tcp://{0}:{1}/CruiseManager.rem", this.Server, this.Port);
                    RemotingServiceAdapter rsa = new RemotingServiceAdapter();
                    ICruiseManager man = (ICruiseManager)rsa.Connect(typeof(ICruiseManager), remotingurl);
                    man.ForceBuild(forcebuild);

                    // clear the cache, one project is building now :D
                    string cacheKey = "cruisecontrol_farminfo_" + this.Server;
                    this.Page.Cache.Remove(cacheKey);
                    this.Page.Response.Redirect(this.Page.Request.Path, true);
                }
                catch (Exception exc) {
                }
            }
        }

        /// <summary>
        /// Create any controls we may need on the Render webpart
        /// </summary>
        protected override void CreateChildControls() {
            base.CreateChildControls();
            CheckForceBuild();
        }

        /// <summary>
        /// Render the CruiseControl information to the output
        /// </summary>
        /// <param name="output">the html output stream of the response</param>
		protected override void RenderWebPart(HtmlTextWriter output) {
			
            output.Write("<style>");
			output.Write(" table.build {width:100%;}");
			output.Write(" table.build,table.build th, table.build td {border-collapse:collapse; }");
			output.Write(" table.build td {border:solid 0px #c0c0ee;padding:2px;4px;2px;4px;} ");
			output.Write(" table.build th{ text-align:left; font-weigth:bold; } span.success{ color:#10dF10 !important; } span.failure{ color:#DF1010 !important;} span.exception{ color:#DF1010 !important; }</style>");
			output.Write("<table class='build'>");
			output.Write("<tr>");
			output.Write("<th>&nbsp;</th><th valign=\"top\">");
			output.Write("CruiseControl Server:");
			output.Write("</th>");
			output.Write("<th colspan=\"3\"><a href=\"http://");
			output.Write(this.Server);
			output.Write("\" target=\"_new\">http://");
            output.Write(this.Server);
            output.Write(":");
            output.Write(this.Port);
            output.Write("</a><br /><br /></th>");
			output.Write("</tr>");
			ArrayList projectlist = this.GetProjectInfo();
            
            if (projectlist != null) {
				projectlist.Sort(new GenericSort("LastBuildDate", "desc"));
				output.Write("<tr><th>");
                output.Write("<img src=\"/_layouts/images/ttcc/visualstudio.gif\" alt=\"VisualStudio\"/>");
				output.Write("</th>");
                if (string.IsNullOrEmpty(this.Category)) {
                    output.Write("<th>Category</th>");
                }
				output.Write("<th>Project</th>");
				output.Write("<th>Label</th>");
				output.Write("<th>Build on</th>");
                output.Write("<th>Next build</th>");
                output.Write("<th></th>");
                output.Write("</tr>");
				foreach (ProjectStatus status in projectlist) {

                    bool allowforceBuild = false;
					output.Write("<tr>");
					output.Write("<td>");
					if (status.Activity == ProjectActivity.Sleeping) {
                        allowforceBuild = true;
						switch (status.BuildStatus) {
							case IntegrationStatus.Success:
                                output.Write("<img src=\"/_layouts/images/ttcc/build_success.gif\" alt=\"Success\"/>");
								break;
							case IntegrationStatus.Failure:
                                output.Write("<img src=\"/_layouts/images/ttcc/build_error.gif\" alt=\"Failure\"/>");
								break;
							case IntegrationStatus.Exception:
                                output.Write("<img src=\"/_layouts/images/ttcc/build_error.gif\" alt=\"Exception occured\"/>");
								break;
							case IntegrationStatus.Unknown:
                                output.Write("<img src=\"/_layouts/images/ttcc/build_warning.gif\" alt=\"Unknown\"/>");
								break;
						}
					}
					else if (status.Activity == ProjectActivity.Building) {
                        output.Write("<img src=\"/_layouts/images/ttcc/build_building.gif\" alt=\"Building\"/>");
					}
					else if (status.Activity == ProjectActivity.CheckingModifications) {
                        output.Write("<img src=\"/_layouts/images/ttcc/build_label.gif\" alt=\"Setting label\"/>");
					}
					output.Write("</td>");
                    if (string.IsNullOrEmpty(this.Category)) {
                        output.Write("<td>");
                        output.Write(status.Category);
                        output.Write("</td>");
                    }
					output.Write("<td><a href=\"");
					output.Write(status.WebURL);
					output.Write("\" target=\"_blank\">");
					output.Write(status.Name);
					output.Write("</a></td>");
					output.Write("<td>");
					output.Write(status.LastBuildLabel);
					output.Write("</td>");
					output.Write("<td>");
					output.Write(status.LastBuildDate.ToString("dd-MM-yyyy HH:mm"));
					output.Write("</td>");
                    output.Write("<td>");
                    output.Write(status.NextBuildTime.ToString("dd-MM-yyyy HH:mm"));
                    output.Write("</td>");
                    output.Write("<td>");
                    if (allowforceBuild) {
                        output.Write("<a href=\"?force=");
                        output.Write(System.Web.HttpUtility.UrlEncode(status.Name));
                        output.Write("\" title=\"Force a build\">Force</a>");
                    }
                    output.Write("</td>");
					
					output.Write("</tr>");
				}
			}
			else {
				output.Write("<tr><td>no connection could be made</td></tr>");
			}
			output.Write("</table>");
		}

        private string server;

        /// <summary>
        /// The servername or IP address of the CruiseControl v1.1 server to contact
        /// </summary>
		[Description("CruiseControl servername or IP"), 
		Browsable(true),
       Category("CruiseControl"), 
		WebPartStorage(Storage.Shared),
       FriendlyName("Server")]
		public string Server {
			get {
				return this.server;
			}
			set {
				this.server = value;
			}
		}

        private int portnumber = 21234;

        /// <summary>
        /// The portnumber to communicate with cruisecontrol
        /// </summary>
        /// <remarks>default is 21234</remarks>
        [Description("CruiseControl serverport"),
        Browsable(true),
       Category("CruiseControl"),
        WebPartStorage(Storage.Shared),
       FriendlyName("Port")]
        public int Port{
            get {
                return this.portnumber;
            }
            set {
                if  ( value==0 )
                    this.portnumber = 21234;
                else
                    this.portnumber = value;
            }
        }

        private string category = "";

        /// <summary>
        /// Filter the projects on a category
        /// </summary>
        [Description("CruiseControl Category filter, leave blank for no filtering"),
        Browsable(true),
       Category("CruiseControl"),
        WebPartStorage(Storage.Shared),
       FriendlyName("Category")]
        public string Category {
            get {
                return this.category;
            }
            set {
                this.category = value;
            }
        }
    
    }
}